{%-set exception %}{{resolver.cpp_get_lib_ns() | join('::')}}::JsonSchemaException{%endset-%}
/*! {{Name}} is a wrapper around a {{schema.type}}.
 {%-if schema.description %}
 * {{schema.description}}
 {%-endif%}
 */
class {{Name}}
{
public:
    {%-if schema.maxLength is defined %}
    /*! The maximum length of the contained string.
     * Trying to set a string longer than this length will throw.
     * It is useful to use this value in a static_assert statement
     * to ensure it is consistant with external requirements.
     */
    static constexpr int MAX_LENGTH = {{schema.maxLength}};
    {%endif%}
    {%-if schema.minLength is defined %}
    /*! The minimum length of the contained string.
     * Trying to set a string shorter than this length will throw.
     * It is useful to use this value in a static_assert statement
     * to ensure it is consistant with external requirements.
     */
    static constexpr int MIN_LENGTH = {{schema.minLength}};
    {%endif%}
    {%-if schema.default is defined or schema.const is defined%}
    /*! The default value of the string.
     * If the string has not been set to a value, "{{schema.default or schema.const}}" would be returned for value getting methods.
     */
    static constexpr auto DEFAULT_VALUE = "{{schema.default or schema.const}}";
    
    {%-endif%}
    {%-if schema.const is defined%}
    /*! The constant value of the string.
     * The value is not allowed to be anything other than "{{schema.const}}".
     */
    static constexpr auto CONST_VALUE = "{{schema.const}}";
    {%-endif%}
    {%-if schema.const is not defined%}

    /*! Constructor.
     * \param value initial value of {{Name}} instance.
     */
    {{Name}}(const std::string& value);

    /*! Constructor.
     * \param value initial value of {{Name}} instance.
     */
    {{Name}}(const char* value);
    {%-endif%}
    {%-if schema.default is defined or schema.const is defined%}

    /*! Constructor that sets the objects value to "{{schema.const or schema.default}}".
     */
    {{Name}}();
    {%-elif schema.format is defined and schema.format == 'uuid'%}

    /*! Constructor that sets the objects value to a new unique UUID.
     */
    {{Name}}();
    {%-endif-%}{# #}
    
    /*! Default destructor.
     */
    virtual ~{{Name}}() = default;

    /*! Operator to cast a {{Name}} instance to a string.
     */
    operator std::string() const;
     /*! Provide the string value of the {{Name}} instance to a stream.
     * \param os the stream object
     * \param str an instance of {{Name}}
     * \return the same ostream input object
     */
    friend std::ostream& operator<<(std::ostream& os, const {{Name}}& str);
    
    /*! The less than comparison operator.
     * \param left A {{Name}} instance on the left size of the less than expression.
     * \param right A {{Name}} instance on the right side of the less than expression.
     * \return true if the less than expression is true.
     */
    friend bool operator< (const {{Name}}& left, const {{Name}}& right);

    /*! Produce a hash value of the string.
     * \param str A {{Name}} instance from which to produce a hash.
     * \return a hash number using a boost hashing algorithm.
     */
    friend std::size_t hash_value(const {{Name}}& str);

    /*! Get the contained string.
     * \return The contained string.
     */
    std::string Get() const;

    /*! Validate that the provided string meets schema constraints.
     * This is used internally anytime a value is passed into the class, including from the constructor.
     * \param testValue string for evaluation
     * \throw {{exception}} If the string doesn't meet requirements
     */
    static void Validate(const std::string& testValue);

    /*! Create a new {{Name}} object from a JSON structure.
     * \throw {{exception}} If the string didn't meet the schema's constraints.
     * \return new {{Name}} object containing values from the JSON.
     * \param json JSON structure to use for creating new {{Name}} object.
     */
    static {{Name}} FromJson(const rapidjson::Value& json);

    /*! Create a new {{Name}} object from the string.
     * The string must meet the schema's constraints.
     * \return new {{Name}} object containing the string.
     * \param str the string that will be contained in the new {{Name}} object.
     * \throw {{exception}} If the JSON value isn't a JSON string.
     * \throw {{exception}} If the string didn't meet the schema's constraints.
     */
    static {{Name}} FromString(const std::string& str);

    /*! Serialize the {{Name}} instance into a JSON object.
     * \param value is modified to be a string type containing the instance's string value.
     * \param allocator is used for rapidjson allocation.
     */
    void ToJson(rapidjson::Value& value, rapidjson::Value::AllocatorType& allocator) const;

    /*! Sets a string handle associated with this {{Name}} instance.
     * This gets called by a parent object after creating an instance that is used for an object's property.
     * \param handle is the string name.
     */
    void SetHandle(const std::string& handle);

    /*! Gets the string handle associated with this {{Name}} instance.
     * This is often the property name used in a JSON-object parent.
     * It may be empty.
     * \returns the handle string
     */
    std::string GetHandle() const;

{%if schema.IsReadOnly() or schema.const is defined %}
private:
{%-endif%}
    /*! Assignment operator to set the value of the {{Name}} instance.
     * \param value the new string value.
     * \throw {{exception}} if the passed string value doesn't meet schema validation.
     * \return reference to the {{Name}} instance
     */
    {{Name}}& operator=(const std::string& value);
    
    /*! Assignment operator to set the value of the {{Name}} instance.
     * \param value the new string value.
     * \throw {{exception}} if the passed string value doesn't meet schema validation.
     * \return reference to the {{Name}} instance
     */
    {{Name}}& operator=(const char* value);

    /*! Set the value of the string.
     * \param value the new string value.
     * \throw {{exception}} If the passed string value doesn't meet schema validation.
     */
    {{Name}}& Set(const std::string& value);

    /*! Set the value of the string.
     * \param value the new string value.
     * \throw {{exception}} If the passed string value doesn't meet schema validation.
     */
    {{Name}}& Set(const char* value);

    {%-if schema.format is defined and schema.format == 'uuid'%}
    /*! Set the encapsulated value of the {{Name}} object to a new UUID.
     */
    {{Name}}& SetUuid();
    {%-endif%}

private:
    std::string _value;
    std::string _handle;
};